﻿using System;
using System.Text;

namespace GeoAPI.Geometries
{
	public class IntersectionMatrix
	{
		public IntersectionMatrix()
		{
			this._matrix = new Dimension[3, 3];
			this.SetAll(Dimension.False);
		}

		public IntersectionMatrix(string elements) : this()
		{
			this.Set(elements);
		}

		public IntersectionMatrix(IntersectionMatrix other) : this()
		{
			this._matrix[0, 0] = other._matrix[0, 0];
			this._matrix[0, 1] = other._matrix[0, 1];
			this._matrix[0, 2] = other._matrix[0, 2];
			this._matrix[1, 0] = other._matrix[1, 0];
			this._matrix[1, 1] = other._matrix[1, 1];
			this._matrix[1, 2] = other._matrix[1, 2];
			this._matrix[2, 0] = other._matrix[2, 0];
			this._matrix[2, 1] = other._matrix[2, 1];
			this._matrix[2, 2] = other._matrix[2, 2];
		}

		public void Add(IntersectionMatrix im)
		{
			for (int i = 0; i < 3; i++)
			{
				for (int j = 0; j < 3; j++)
				{
					this.SetAtLeast((Location)i, (Location)j, im.Get((Location)i, (Location)j));
				}
			}
		}

		public static bool IsTrue(Dimension actualDimensionValue)
		{
			return actualDimensionValue >= Dimension.Point || actualDimensionValue == Dimension.True;
		}

		public static bool Matches(Dimension actualDimensionValue, char requiredDimensionSymbol)
		{
			return requiredDimensionSymbol == '*' || (requiredDimensionSymbol == 'T' && (actualDimensionValue >= Dimension.Point || actualDimensionValue == Dimension.True)) || (requiredDimensionSymbol == 'F' && actualDimensionValue == Dimension.False) || (requiredDimensionSymbol == '0' && actualDimensionValue == Dimension.Point) || (requiredDimensionSymbol == '1' && actualDimensionValue == Dimension.Curve) || (requiredDimensionSymbol == '2' && actualDimensionValue == Dimension.Surface);
		}

		public static bool Matches(string actualDimensionSymbols, string requiredDimensionSymbols)
		{
			IntersectionMatrix intersectionMatrix = new IntersectionMatrix(actualDimensionSymbols);
			return intersectionMatrix.Matches(requiredDimensionSymbols);
		}

		public void Set(Location row, Location column, Dimension dimensionValue)
		{
			this._matrix[(int)row, (int)column] = dimensionValue;
		}

		public void Set(string dimensionSymbols)
		{
			for (int i = 0; i < dimensionSymbols.Length; i++)
			{
				int num = i / 3;
				int num2 = i % 3;
				this._matrix[num, num2] = DimensionUtility.ToDimensionValue(dimensionSymbols[i]);
			}
		}

		public void SetAtLeast(Location row, Location column, Dimension minimumDimensionValue)
		{
			if (this._matrix[(int)row, (int)column] < minimumDimensionValue)
			{
				this._matrix[(int)row, (int)column] = minimumDimensionValue;
			}
		}

		public void SetAtLeastIfValid(Location row, Location column, Dimension minimumDimensionValue)
		{
			if (row >= Location.Interior && column >= Location.Interior)
			{
				this.SetAtLeast(row, column, minimumDimensionValue);
			}
		}

		public void SetAtLeast(string minimumDimensionSymbols)
		{
			for (int i = 0; i < minimumDimensionSymbols.Length; i++)
			{
				int row = i / 3;
				int column = i % 3;
				this.SetAtLeast((Location)row, (Location)column, DimensionUtility.ToDimensionValue(minimumDimensionSymbols[i]));
			}
		}

		public void SetAll(Dimension dimensionValue)
		{
			for (int i = 0; i < 3; i++)
			{
				for (int j = 0; j < 3; j++)
				{
					this._matrix[i, j] = dimensionValue;
				}
			}
		}

		public Dimension Get(Location row, Location column)
		{
			return this._matrix[(int)row, (int)column];
		}

		public Dimension this[Location row, Location column]
		{
			get
			{
				return this.Get(row, column);
			}
			set
			{
				this.Set(row, column, value);
			}
		}

		public bool IsDisjoint()
		{
			return this._matrix[0, 0] == Dimension.False && this._matrix[0, 1] == Dimension.False && this._matrix[1, 0] == Dimension.False && this._matrix[1, 1] == Dimension.False;
		}

		public bool IsIntersects()
		{
			return !this.IsDisjoint();
		}

		public bool IsTouches(Dimension dimensionOfGeometryA, Dimension dimensionOfGeometryB)
		{
			if (dimensionOfGeometryA > dimensionOfGeometryB)
			{
				return this.IsTouches(dimensionOfGeometryB, dimensionOfGeometryA);
			}
			return ((dimensionOfGeometryA == Dimension.Surface && dimensionOfGeometryB == Dimension.Surface) || (dimensionOfGeometryA == Dimension.Curve && dimensionOfGeometryB == Dimension.Curve) || (dimensionOfGeometryA == Dimension.Curve && dimensionOfGeometryB == Dimension.Surface) || (dimensionOfGeometryA == Dimension.Point && dimensionOfGeometryB == Dimension.Surface) || (dimensionOfGeometryA == Dimension.Point && dimensionOfGeometryB == Dimension.Curve)) && this._matrix[0, 0] == Dimension.False && (IntersectionMatrix.IsTrue(this._matrix[0, 1]) || IntersectionMatrix.IsTrue(this._matrix[1, 0]) || IntersectionMatrix.IsTrue(this._matrix[1, 1]));
		}

		public bool IsCrosses(Dimension dimensionOfGeometryA, Dimension dimensionOfGeometryB)
		{
			if ((dimensionOfGeometryA == Dimension.Point && dimensionOfGeometryB == Dimension.Curve) || (dimensionOfGeometryA == Dimension.Point && dimensionOfGeometryB == Dimension.Surface) || (dimensionOfGeometryA == Dimension.Curve && dimensionOfGeometryB == Dimension.Surface))
			{
				return IntersectionMatrix.IsTrue(this._matrix[0, 0]) && IntersectionMatrix.IsTrue(this._matrix[0, 2]);
			}
			if ((dimensionOfGeometryA == Dimension.Curve && dimensionOfGeometryB == Dimension.Point) || (dimensionOfGeometryA == Dimension.Surface && dimensionOfGeometryB == Dimension.Point) || (dimensionOfGeometryA == Dimension.Surface && dimensionOfGeometryB == Dimension.Curve))
			{
				return IntersectionMatrix.IsTrue(this._matrix[0, 0]) && IntersectionMatrix.IsTrue(this._matrix[2, 0]);
			}
			return dimensionOfGeometryA == Dimension.Curve && dimensionOfGeometryB == Dimension.Curve && this._matrix[0, 0] == Dimension.Point;
		}

		public bool IsWithin()
		{
			return IntersectionMatrix.IsTrue(this._matrix[0, 0]) && this._matrix[0, 2] == Dimension.False && this._matrix[1, 2] == Dimension.False;
		}

		public bool IsContains()
		{
			return IntersectionMatrix.IsTrue(this._matrix[0, 0]) && this._matrix[2, 0] == Dimension.False && this._matrix[2, 1] == Dimension.False;
		}

		public bool IsCovers()
		{
			bool flag = IntersectionMatrix.IsTrue(this._matrix[0, 0]) || IntersectionMatrix.IsTrue(this._matrix[0, 1]) || IntersectionMatrix.IsTrue(this._matrix[1, 0]) || IntersectionMatrix.IsTrue(this._matrix[1, 1]);
			return flag && this._matrix[2, 0] == Dimension.False && this._matrix[2, 1] == Dimension.False;
		}

		public bool IsCoveredBy()
		{
			bool flag = IntersectionMatrix.Matches(this._matrix[0, 0], 'T') || IntersectionMatrix.Matches(this._matrix[0, 1], 'T') || IntersectionMatrix.Matches(this._matrix[1, 0], 'T') || IntersectionMatrix.Matches(this._matrix[1, 1], 'T');
			return flag && this._matrix[0, 2] == Dimension.False && this._matrix[1, 2] == Dimension.False;
		}

		public bool IsEquals(Dimension dimensionOfGeometryA, Dimension dimensionOfGeometryB)
		{
			return dimensionOfGeometryA == dimensionOfGeometryB && (IntersectionMatrix.IsTrue(this._matrix[0, 0]) && this._matrix[0, 2] == Dimension.False && this._matrix[1, 2] == Dimension.False && this._matrix[2, 0] == Dimension.False) && this._matrix[2, 1] == Dimension.False;
		}

		public bool IsOverlaps(Dimension dimensionOfGeometryA, Dimension dimensionOfGeometryB)
		{
			if ((dimensionOfGeometryA == Dimension.Point && dimensionOfGeometryB == Dimension.Point) || (dimensionOfGeometryA == Dimension.Surface && dimensionOfGeometryB == Dimension.Surface))
			{
				return IntersectionMatrix.IsTrue(this._matrix[0, 0]) && IntersectionMatrix.IsTrue(this._matrix[0, 2]) && IntersectionMatrix.IsTrue(this._matrix[2, 0]);
			}
			return dimensionOfGeometryA == Dimension.Curve && dimensionOfGeometryB == Dimension.Curve && (this._matrix[0, 0] == Dimension.Curve && IntersectionMatrix.IsTrue(this._matrix[0, 2])) && IntersectionMatrix.IsTrue(this._matrix[2, 0]);
		}

		public bool Matches(string requiredDimensionSymbols)
		{
			if (requiredDimensionSymbols.Length != 9)
			{
				throw new ArgumentException("Should be length 9: " + requiredDimensionSymbols);
			}
			for (int i = 0; i < 3; i++)
			{
				for (int j = 0; j < 3; j++)
				{
					if (!IntersectionMatrix.Matches(this._matrix[i, j], requiredDimensionSymbols[3 * i + j]))
					{
						return false;
					}
				}
			}
			return true;
		}

		public IntersectionMatrix Transpose()
		{
			Dimension dimension = this._matrix[1, 0];
			this._matrix[1, 0] = this._matrix[0, 1];
			this._matrix[0, 1] = dimension;
			dimension = this._matrix[2, 0];
			this._matrix[2, 0] = this._matrix[0, 2];
			this._matrix[0, 2] = dimension;
			dimension = this._matrix[2, 1];
			this._matrix[2, 1] = this._matrix[1, 2];
			this._matrix[1, 2] = dimension;
			return this;
		}

		public override string ToString()
		{
			StringBuilder stringBuilder = new StringBuilder("123456789");
			for (int i = 0; i < 3; i++)
			{
				for (int j = 0; j < 3; j++)
				{
					stringBuilder[3 * i + j] = DimensionUtility.ToDimensionSymbol(this._matrix[i, j]);
				}
			}
			return stringBuilder.ToString();
		}

		private readonly Dimension[,] _matrix;
	}
}
